package myJs.user.workflow.featureSelection.diagnoseAna

import com.softwaremill.quicklens._
import myJs.Implicits._
import myJs.cps.{InputCp, SelectCp, ToggleCp}
import myJs.myPkg.reactHookForm.{ReactHookForm, UseFormRT}
import myJs.tool.Tool
import myJs.tool.Tool._
import myJs.user.workflow.featureSelection.{FeatureSelection, FileSelectCp}
import shared.Pojo.MetDataKind
import shared.pojo.Pojo
import shared.pojo.WorkflowMission._

import scala.collection.immutable.SeqMap
import scala.scalajs.js

import japgolly.scalajs.react.vdom.all._
import japgolly.scalajs.react._
import japgolly.scalajs.react.React.Fragment
import japgolly.scalajs.react.util.EffectCatsEffect._
import myJs.myPkg.Hooks._
import cats.effect._
import myJs.Implicits._

/** Created by yz on 3/11/2020
  */
object DiagnoseAnaCp {

  case class Props(
      curI: Int,
      data: EachDiagnoseAnaData,
      dataChange: EachDiagnoseAnaData => SyncIO[Unit],
      dataModifyF: (EachDiagnoseAnaData=>EachDiagnoseAnaData) => SyncIO[Unit],
      extraData: ExtraData,
      extraDataChange: ExtraData => SyncIO[Unit],
      fsData:FsData
  ){
    @inline def render: VdomElement = {
      Component(this)
    }
  }

  val Component = ScalaFnComponent[Props] { props =>
    val useForm=ReactHookForm.useFormContext()
    val curTool = DiagnoseAna
    val namePrefix = s"diagnoseAna.${props.curI}"

    object FTool {

      def scaleMethodChange = (v: String) => {
        val newData = props.data.modify(_.scaleMethod).setTo(v)
        props.dataChange(newData)
      }

      def groupModifyF = (v: String) => {
        val newData = modifyLens[EachDiagnoseAnaData](_.group).setTo(v)
        props.dataModifyF(newData)
      }

      def hasExternalChange = (v: Boolean) => {
        val newData = props.data.modify(_.hasExternal).setTo(v)
        props.dataChange(newData)
      }

      def externalPreprocessChange = (v: String) => {
        val newData = props.data.modify(_.externalPreprocess).setTo(v)
        props.dataChange(newData)
      }

      def hasCvChange = (v: Boolean) => {
        val newData = props.data.modify(_.hasCv).setTo(v)
        props.dataChange(newData)
      }

      def kChange = (v: String) => {
        val newData = props.data.modify(_.k).setTo(v)
        props.dataChange(newData)
      }

      def externalFileSelect = (v: String) => {
        val newExtraData = props.extraData
          .modify(_.fileSelectShow)
          .setTo(false)
        props.extraDataChange(newExtraData)
        val newData = props.data
          .modify(_.externalFile)
          .setTo(v)
          .modify(_.externalGroupFile)
          .setTo("")
        props.dataChange(newData)
        useForm.setValue(s"${namePrefix}.externalFile", v)
        useForm.setValue(s"${namePrefix}.externalGroupFile", "")
        useForm.trigger(s"${namePrefix}.externalGroupFile")
      }

      def externalGroupFileSelect = (v: String) => {
        val newExtraData = props.extraData
          .modify(_.fileSelectShow)
          .setTo(false)
        props.extraDataChange(newExtraData)
        val newData = props.data
          .modify(_.externalGroupFile)
          .setTo(v)
        props.dataChange(newData)
        useForm.setValue(s"${namePrefix}.externalGroupFile", v)
      }

      def fileSelectShow = {
        val newData = props.extraData
          .modify(_.tabs)
          .setTo(List(MetDataKind.name))
          .modify(_.fileSelectShow)
          .setTo(true)
          .modify(_.fileSelect)
          .setTo(FTool.externalFileSelect)
        props.extraDataChange(newData)
      }

      def externalGroupFileSelectShow = {
        val newRequest =
          Pojo.groupFileData.GetAll.Request(id = FeatureSelection.getId, fileName = props.data.externalFile)
        val newData = props.extraData
          .modify(_.tabs)
          .setTo(List("group"))
          .modify(_.fileSelectShow)
          .setTo(true)
          .modify(_.request)
          .setTo(newRequest)
          .modify(_.fileSelect)
          .setTo(FTool.externalGroupFileSelect)
        props.extraDataChange(newData)
      }

      def runRfChange = (v: Boolean) => {
        val newData = props.data.modify(_.runRf).setTo(v)
        props.dataChange(newData)
      }

      def ntreeChange = (v: String) => {
        val newData = props.data.modify(_.ntree).setTo(v)
        props.dataChange(newData)
      }

      def replaceChange = (v: String) => {
        val newData = props.data.modify(_.replace).setTo(v)
        props.dataChange(newData)
      }

      def hasMtryChange = (v: Boolean) => {
        val newData = props.data.modify(_.hasMtry).setTo(v)
        props.dataChange(newData)
      }

      def mtryChange = (v: String) => {
        val newData = props.data.modify(_.mtry).setTo(v)
        props.dataChange(newData)
      }

      def hasNodesizeChange = (v: Boolean) => {
        val newData = props.data.modify(_.hasNodesize).setTo(v)
        props.dataChange(newData)
      }

      def nodesizeChange = (v: String) => {
        val newData = props.data.modify(_.nodesize).setTo(v)
        props.dataChange(newData)
      }

      def hasMaxnodeChange = (v: Boolean) => {
        val newData = props.data.modify(_.hasMaxnode).setTo(v)
        props.dataChange(newData)
      }

      def maxnodeChange = (v: String) => {
        val newData = props.data.modify(_.maxnode).setTo(v)
        props.dataChange(newData)
      }

      def runGbChange = (v: Boolean) => {
        val newData = props.data.modify(_.runGb).setTo(v)
        props.dataChange(newData)
      }

      def distributionChange = (v: String) => {
        val newData = props.data.modify(_.distribution).setTo(v)
        props.dataChange(newData)
      }

      def gbNTreeChange = (v: String) => {
        val newData = props.data.modify(_.gbNTree).setTo(v)
        props.dataChange(newData)
      }

      def depthChange = (v: String) => {
        val newData = props.data.modify(_.depth).setTo(v)
        props.dataChange(newData)
      }

      def fractionChange = (v: String) => {
        val newData = props.data.modify(_.fraction).setTo(v)
        props.dataChange(newData)
      }

      def runLrChange = (v: Boolean) => {
        val newData = props.data.modify(_.runLr).setTo(v)
        props.dataChange(newData)
      }

      def runSvmChange = (v: Boolean) => {
        val newData = props.data.modify(_.runSvm).setTo(v)
        props.dataChange(newData)
      }

      def kernelChange = (v: String) => {
        val newData = props.data.modify(_.kernel).setTo(v)
        props.dataChange(newData)
      }

      def costChange = (v: String) => {
        val newData = props.data.modify(_.cost).setTo(v)
        props.dataChange(newData)
      }

      def toleranceChange = (v: String) => {
        val newData = props.data.modify(_.tolerance).setTo(v)
        props.dataChange(newData)
      }

      def epsilonChange = (v: String) => {
        val newData = props.data.modify(_.epsilon).setTo(v)
        props.dataChange(newData)
      }

      def gammaChange = (v: String) => {
        val newData = props.data.modify(_.gamma).setTo(v)
        props.dataChange(newData)
      }

      def coef0Change = (v: String) => {
        val newData = props.data.modify(_.coef0).setTo(v)
        props.dataChange(newData)
      }

      def degreeChange = (v: String) => {
        val newData = props.data.modify(_.degree).setTo(v)
        props.dataChange(newData)
      }

      def runEnChange = (v: Boolean) => {
        val newData = props.data.modify(_.runEn).setTo(v)
        props.dataChange(newData)
      }

    }

    useEffect(
      SyncIO{
        Tool.refreshNodeColor(props.data.nodeId, useForm.formState, namePrefix)
      },
      List(useForm.formState)
    )

    val dataMatrixGroups= props.fsData.dataMatrix.groups
    val groupMap = Tool.getGroupVs(dataMatrixGroups).optionMap
    val isMul = dataMatrixGroups.size != 2
    val externalPreprocessMap =
      SeqMap("T" -> messages("performSameProcessing"), "F" -> messages("skipExternalDataHasProcessed"))
    val kMap = List("3", "7", "10").optionMap
    val data = props.data
    val replaceMap = SeqMap("T" -> messages("yes"), "F" -> messages("no"))
    val distributions = List("multinomial", "gaussian", "laplace", "tdist", "bernoulli")
    val distributionMap = distributions.map { x =>
      (x, x)
    }.toSeqMap
    val kernelMap =
      SeqMap("linear" -> "linear", "polynomial" -> "polynomial", "radial" -> "radial", "sigmoid" -> "sigmoid")

    div(
      SelectCp.Props(
        value = props.data.scaleMethod,
        label = messages("scaleMethod"),
        name = s"${namePrefix}.scaleMethod",
        optionMap = scaleMethodMap,
        onChange = FTool.scaleMethodChange
      ).render,
      SelectCp.Props(
        value = props.data.group,
        label = messages("group"),
        name = s"${namePrefix}.group",
        optionMap = groupMap,
        onChange = FTool.groupModifyF,
        show = isMul
      ).render,
      ToggleCp.Props(
        value = props.data.hasCv,
        label = messages("execCv"),
        name = s"${namePrefix}.hasCv",
        valueChange = FTool.hasCvChange
      ).render,
      SelectCp.Props(
        value = props.data.k,
        label = messages("foldsK"),
        name = s"${namePrefix}.k",
        optionMap = kMap,
        onChange = FTool.kChange,
        show = data.hasCv
      ).render,
      ToggleCp.Props(
        value = props.data.hasExternal,
        label = messages("importExternalData"),
        name = s"${namePrefix}.hasExternal",
        valueChange = FTool.hasExternalChange
      ).render,
      SelectCp.Props(
        value = props.data.externalPreprocess,
        label = messages("externalDataProcessing"),
        name = s"${namePrefix}.externalPreprocess",
        optionMap = externalPreprocessMap,
        onChange = FTool.externalPreprocessChange,
        show = props.data.hasExternal
      ).render,
      FileSelectCp.Props(
        fileSelectShow = FTool.fileSelectShow,
        label = messages("externalData"),
        name = s"${namePrefix}.externalFile",
        value = props.data.externalFile,
        show = props.data.hasExternal
      ).render,
      FileSelectCp.Props(
        fileSelectShow = FTool.externalGroupFileSelectShow,
        label = messages("externalGroupFile"),
        name = s"${namePrefix}.externalGroupFile",
        value = data.externalGroupFile,
        show = props.data.hasExternal
      ).render,
      div(className := "form-group col-sm-12", hr()),
      h4(messages("randomForestModel")),
      ToggleCp.Props(
        value = props.data.runRf,
        label = messages("runRf"),
        name = s"${namePrefix}.runRf",
        valueChange = FTool.runRfChange
      ).render,
      InputCp.Props(
        value = data.ntree,
        show = data.runRf,
        label = messages("numberOfTreesToGrow"),
        name = s"${namePrefix}.ntree",
        onChange = FTool.ntreeChange
      ).render,
      SelectCp.Props(
        value = props.data.replace,
        label = messages("samplingWithReplacement"),
        name = s"${namePrefix}.replace",
        optionMap = replaceMap,
        onChange = FTool.replaceChange,
        show = data.runRf
      ).render,
      ToggleCp.Props(
        value = props.data.hasMtry,
        label = messages("setVariablesNumber"),
        name = s"${namePrefix}.hasMtry",
        valueChange = FTool.hasMtryChange,
        show = data.runRf
      ).render,
      InputCp.Props(
        value = props.data.mtry,
        show = (data.runRf && data.hasMtry),
        label = messages("variablesNumber"),
        name = s"${namePrefix}.mtry",
        onChange = FTool.mtryChange
      ).render,
      ToggleCp.Props(
        value = props.data.hasNodesize,
        label = messages("setMinimumNodesize"),
        name = s"${namePrefix}.hasNodesize",
        valueChange = FTool.hasNodesizeChange,
        show = data.runRf
      ).render,
      InputCp.Props(
        value = props.data.nodesize,
        show = (data.runRf && data.hasNodesize),
        label = messages("nodesMinimumSize"),
        name = s"${namePrefix}.nodesize",
        onChange = FTool.nodesizeChange
      ).render,
      ToggleCp.Props(
        value = props.data.hasMaxnode,
        label = messages("setMaximumNumber"),
        name = s"${namePrefix}.hasMaxnode",
        valueChange = FTool.hasMaxnodeChange,
        show = data.runRf
      ).render,
      InputCp.Props(
        value = props.data.maxnode,
        show = (data.runRf && data.hasMaxnode),
        label = messages("nodesMaximumNumber"),
        name = s"${namePrefix}.maxnode",
        onChange = FTool.maxnodeChange
      ).render,
      div(className := "form-group col-sm-12", hr()),
      h4(messages("gradientBoostingModel")),
      ToggleCp.Props(
        value = data.runGb,
        label = messages("runGb"),
        name = s"${namePrefix}.runGb",
        valueChange = FTool.runGbChange
      ).render,
      SelectCp.Props(
        value = data.distribution,
        label = messages("samplingWithReplacement"),
        name = s"${namePrefix}.distribution",
        optionMap = distributionMap,
        onChange = FTool.distributionChange,
        show = data.runGb
      ).render,
      InputCp.Props(
        value = data.gbNTree,
        show = data.runGb,
        label = "n.trees",
        name = s"${namePrefix}.gbNTree",
        onChange = FTool.gbNTreeChange
      ).render,
      InputCp.Props(
        value = data.depth,
        show = data.runGb,
        label = "interaction.depth",
        name = s"${namePrefix}.depth",
        onChange = FTool.depthChange
      ).render,
      InputCp.Props(
        value = data.fraction,
        show = data.runGb,
        label = "bag.fraction",
        name = s"${namePrefix}.fraction",
        onChange = FTool.fractionChange
      ).render,
      div(className := "form-group col-sm-12", hr()),
      h4(messages("logisticRegressionModel")),
     ToggleCp.Props(
        value = data.runLr,
        label = messages("runLr"),
        name = s"${namePrefix}.runLr",
        valueChange = FTool.runLrChange
      ).render,
      div(className := "form-group col-sm-12", hr()),
      h4(messages("sVMModel")),
     ToggleCp.Props(
        value = data.runSvm,
        label = messages("runSvm"),
        name = s"${namePrefix}.runSvm",
        valueChange = FTool.runSvmChange
      ).render,
      SelectCp.Props(
        value = props.data.kernel,
        label = messages("kernelFunction"),
        name = s"${namePrefix}.kernel",
        optionMap = kernelMap,
        onChange = FTool.kernelChange,
        show = data.runSvm
      ).render,
      InputCp.Props(
        value = props.data.cost,
        show = data.runSvm,
        label = "cost",
        name = s"${namePrefix}.cost",
        onChange = FTool.costChange
      ).render,
      InputCp.Props(
        value = props.data.tolerance,
        show = data.runSvm,
        label = "tolerance",
        name = s"${namePrefix}.tolerance",
        onChange = FTool.toleranceChange
      ).render,
      InputCp.Props(
        value = props.data.epsilon,
        show = data.runSvm,
        label = "epsilon",
        name = s"${namePrefix}.epsilon",
        onChange = FTool.epsilonChange
      ).render,
      InputCp.Props(
        value = props.data.gamma,
        show = (data.runSvm && (data.kernel != "linear")),
        label = "gamma",
        name = s"${namePrefix}.gamma",
        onChange = FTool.gammaChange
      ).render,
      InputCp.Props(
        value = props.data.coef0,
        show = (data.runSvm && List("polynomial", "sigmoid").contains(data.kernel)),
        label = "coef0",
        name = s"${namePrefix}.coef0",
        onChange = FTool.coef0Change
      ).render,
      InputCp.Props(
        value = props.data.degree,
        show = (data.runSvm && (props.data.kernel == "polynomial")),
        label = "degree",
        name = s"${namePrefix}.degree",
        onChange = FTool.degreeChange
      ).render,
      div(className := "form-group col-sm-12", hr()),
      h4(messages("enModel")),
     ToggleCp.Props(
        value = data.runEn,
        label = messages("runElasticNet"),
        name = s"${namePrefix}.runEn",
        valueChange = FTool.runEnChange
      ).render
    )

  }

}
